//
// Created by htlin on 2021/3/2 0002.
//

#include "ThreadPool.h"
#include "Runnable.h"
#include <cstdlib>
#include <unordered_map>
#include <bits/unordered_set.h>

class ThreadPoolPrivateData {
public:
    uv_loop_t *loop{};
    std::unordered_set<uv_work_t *> requestSet;
};

ThreadPool::ThreadPool() {
  data = std::unique_ptr<ThreadPoolPrivateData>(new ThreadPoolPrivateData());
  data->loop = uv_default_loop();
}

ThreadPool::~ThreadPool() {
  clear();
}

void ThreadPool::start(Runnable *runnable) {
  runnable->setFinishedCallBack(ThreadPool::removeRequestCB, static_cast<void *>(this));
  auto *request = static_cast<uv_work_t *>(malloc(sizeof(uv_work_t)));
  request->data = static_cast<void *>(runnable);
  uv_queue_work(data->loop, request, Runnable::runCB, Runnable::finishCB);
  saveRequestData(request);
}

int ThreadPool::getMaxThreadCount() {
  char *env = getenv(MAX_THREAD_COUNT_VIR);
  if (nullptr == env) {
    return DEFAULT_UV_THREAD_COUNT;
  }
  return atoi(env);
}

void ThreadPool::setMaxThreadCount(int count) {
  char str[64] = {0x00};
  snprintf(str, sizeof(str), "%s=%d", MAX_THREAD_COUNT_VIR, count);
  putenv(str);
}

void ThreadPool::clear() {
  std::unordered_set<uv_work_t *>::iterator iter = data->requestSet.begin();
  for (; iter != data->requestSet.end(); ++iter) {
    uv_cancel((uv_req_t*)*iter);
  }
}

void ThreadPool::saveRequestData(uv_work_t *request) {
  data->requestSet.insert(request);
}

void ThreadPool::removeRequestCB(uv_work_t *request, void *data) {
  auto thisPointer = static_cast<ThreadPool *>(data);
  thisPointer->removeRequest(request);
}

void ThreadPool::removeRequest(uv_work_t *request) {
  data->requestSet.erase(request);
}
